import Message from "./component/message.vue";
import { PluginObject, VNode } from "vue";
import Vue from "vue/types/vue";

interface GlobalOptions {
  verticalOffset?: number;
  flat?: boolean;
  position?: "left" | "center" | "right";
  width?: string | number;
}

interface MessageOptions {
  type: "success" | "error" | "warning" | "info";
  message: string;
  callback?(): void;
}

declare module "vue/types/vue" {
  interface Vue {
    $message(options: MessageOptions): void;
  }
}

const MESSAGE: PluginObject<any> = {
  duration: 2000,
  animateTime: 600,
  instances: [],
  install(Vue, globalOptions: GlobalOptions = {}) {
    function msg(options: MessageOptions) {
      const currOptions: GlobalOptions = {};
      currOptions.verticalOffset =
        globalOptions.verticalOffset === 0 || globalOptions.verticalOffset
          ? globalOptions.verticalOffset
          : 40;
      currOptions.flat = globalOptions.flat || false;
      currOptions.position = globalOptions.position || "right";
      currOptions.width = globalOptions.width || "30%";

      const VueMessage = Vue.extend({
        data() {
          return {
            show: false,
          };
        },
        render(h): VNode {
          const props = {
            type: options.type,
            message: options.message,
            show: this.show,
            flat: currOptions.flat,
            position: currOptions.position,
            width: currOptions.width,
          };
          return h(Message, { props });
        },
      });

      const newMessage = new VueMessage();
      let vm: typeof newMessage | null = newMessage.$mount();
      const el = vm.$el;
      document.body.appendChild(el);

      let verticalOffset = currOptions.verticalOffset;
      const offsetTopArr: number[] = [];
      if (MESSAGE.instances.length) {
        const itemHeight = MESSAGE.instances[0].$el.offsetHeight + 8;
        MESSAGE.instances.forEach((item: any) => {
          offsetTopArr.push(item.$el.offsetTop);
        });
        offsetTopArr.sort((prev, next) => prev - next);
        if (offsetTopArr[0] !== verticalOffset) {
          offsetTopArr.unshift(verticalOffset - itemHeight);
        }

        verticalOffset =
          offsetTopArr.reduce((prev, next) => {
            if (next - prev > itemHeight) {
              return prev;
            } else {
              return next;
            }
          }) + itemHeight;
      }
      const child: any = vm.$children[0];
      child.verticalOffset = verticalOffset;

      vm.show = true;
      MESSAGE.instances.push(vm);
      const t1 = setTimeout(() => {
        clearTimeout(t1);
        vm!.show = false;
        const t2 = setTimeout(() => {
          clearTimeout(t2);
          document.body.removeChild(el);
          newMessage.$destroy();
          vm = null;
          options.callback && options.callback();
          MESSAGE.instances.shift();
        }, MESSAGE.animateTime);
      }, MESSAGE.duration);
    }

    Vue.prototype.$message = msg;
  },
};
export default MESSAGE;
